export default class CustomTransform {
  constructor({ sandbox, size = 1 }) {
    this.sandbox = sandbox
    this.scene = sandbox.scene
    this._size = size
    this._show = false // 整体
    this.orginModelPos = {}

    // 控件轴的显隐状态
    this.axisVisibility = {
      x: { translate: false, rotate: false, scale: false },
      y: { translate: false, rotate: false, scale: false },
      z: { translate: false, rotate: false, scale: false }
    }
    // 默认事件类型
    this.defaultEventType = 'rotationAngle-changed'
    this.marker1 = null // marker 供外面使用，因为orginModelPos旋转超过一圈后不会累加位置
    this.marker2 = null
    this.overlay = new GC.Object3D()
    this.initOverlay()
  }

  initOverlay() {
    const { camera, renderer } = this.sandbox
    const controlsConfig = [
      { translate: { size: 1 * this._size, space: 'local' } },
      // { rotate: { size: 0.8 * this._size, space: 'world' } },
      { rotate: { size: 0.8 * this._size, space: 'local' } },
      { scale: { size: 1.3 * this._size, space: 'local' } }
    ]

    controlsConfig.forEach(controlConfig => {
      const [key, { size, space }] = Object.entries(controlConfig)[0]

      const control = new GC.CustomTransformControls(camera, renderer.domElement)
      control.visible = this._show
      control.controlType = key
      control.setMode(key)
      control.setSpace(space)
      control.size = size

      control.traverse(child => {
        // 自定义属性标记，防止射线检测物体时候，检测到控件
        child.userData.ignoreRaycast = true
      })

      this.overlay.add(control)
      // 设置回调监听事件
      this.setupControlEvents(control)
    })
    this.scene.add(this.overlay)
    this.setupGlobalEventListeners()
  }

  // 局部事件
  setupControlEvents(control) {
    // control.addEventListener(this.defaultEventType, event => {
    //   this.callback?.(event)
    // })

    // 处理 dragging-changed 事件
    control.addEventListener('dragging-changed', this.onDraggingChanged.bind(this))
    control.addEventListener('mouseDown', () => this.toggleVisibility(false))
    control.addEventListener('mouseUp', () => this.toggleVisibility(true))
  }

  registerRotationChangeCallback(callback, eventType = this.defaultEventType) {
    this.callback = callback // 保存回调函数

    // 重新为控件添加事件监听，以使用新的事件类型
    this.overlay.children.forEach((control, index) => {
      // 不需要移除 dragging-changed 的监听器
      control.removeEventListener(this.defaultEventType, this.callback)

      control.addEventListener(eventType, event => {
        // console.log('control', control)
        if (control.object && !Object.keys(this.orginModelPos).length) {
          this.orginModelPos = {
            translate: JSON.parse(JSON.stringify(control.object.position)),
            rotate: JSON.parse(JSON.stringify(control.object.rotation)),
            scale: JSON.parse(JSON.stringify(control.object.scale))
          }
        }
        const modelPos = {
          translate: event.target.object.position,
          rotate: event.target.object.rotation,
          scale: event.target.object.scale
        }

        const enhancedEvent = {
          ...event,
          control,
          modelPos,
          orginModelPos: this.orginModelPos,
          controlIndex: index
          // activeAxis: control.rotationAxis
        }

        this.callback(enhancedEvent)
      })
    })
  }

  onDraggingChanged(event) {
    this.sandbox.controls.enabled = !event.value
  }

  toggleVisibility(visible) {
    if (!this.attachObj) return

    this.overlay.children.forEach(item => {
      if (!item.dragging) {
        item.enabled = visible
        item.visible = visible
      }
      // 鼠标抬起后，恢复刚才操作的控件的模型 lock
      if (visible && item.dragging) {
        item.updateModelLocation = true
      }
    })
    // 鼠标抬起后，清空给定的标记数据
    if (visible) {
      this.orginModelPos = {}
      this.marker1 = null
      this.marker2 = null
    }
  }

  // 全局键盘事件
  setupGlobalEventListeners() {
    this.handleKeyDown = this.handleKeyDown.bind(this)
    this.handleKeyUp = this.handleKeyUp.bind(this)

    window.addEventListener('keydown', this.handleKeyDown)
    window.addEventListener('keyup', this.handleKeyUp)
  }

  handleKeyDown(event) {
    if (!this.attachObj) return
    const arr = this.overlay.children

    switch (event.key) {
      case 'q': // 切换世界/本地空间
        arr.forEach(item => {
          item.setSpace(item.space === 'local' ? 'world' : 'local')
        })
        break

      case 'Shift': // 切换网格
        arr.forEach(item => {
          item.setTranslationSnap(1)
          item.setRotationSnap(GC.MathUtils.degToRad(15))
          item.setScaleSnap(0.25)
        })
        break

      case ' ':
        arr.forEach(item => {
          item.enabled = !item.enabled
        })
        break

      case 'Escape':
        arr.forEach(item => {
          item.reset()
        })
        break
    }
  }

  handleKeyUp(event) {
    if (!this.attachObj) return
    const arr = this.overlay.children

    switch (event.key) {
      case 'Shift':
        arr.forEach(item => {
          item.setTranslationSnap(null)
          item.setRotationSnap(null)
          item.setScaleSnap(null)
        })
        break
    }
  }

  attach(mesh) {
    this.attachObj = mesh
    this.overlay.children.forEach(control => {
      control.attach(mesh)
    })
  }

  detach() {
    this.attachObj = null
    this.overlay.children.forEach(control => {
      control.detach()
      control.removeEventListener(this.defaultEventType, this.callback)
    })
  }

  destroy() {
    // 移除全局事件监听器
    window.removeEventListener('keydown', this.handleKeyDown)
    window.removeEventListener('keyup', this.handleKeyUp)
    this.detach()
    this.overlay.dispose()
  }

  space() {
    this.overlay.children.forEach(item => {
      item.setSpace(item.space === 'local' ? 'world' : 'local')
    })
  }

  // 通用方法来设置轴的显隐状态
  setAxisVisibility(type, axis, value) {
    this.axisVisibility[axis][type] = value
    const control = this.overlay.children.find(item => item.controlType === type)
    if (control) {
      control[`show${axis.toUpperCase()}`] = value
    }
  }

  // 设置单个控件的单个轴线显示隐藏
  // controlType ：translate  rotate  scale
  // axis：   X Y  Z
  setControlAxisVisibility(controlType, axis, visible) {
    const control = this.overlay.children.find(item => item.controlType === controlType.toLowerCase())

    if (control) {
      control[`show${axis.toUpperCase()}`] = visible
      this.axisVisibility[axis][controlType.toLowerCase()] = visible // 更新轴的显隐状态
    }
  }

  // --------
  get size() {
    return this._size
  }

  set size(val) {
    this._size = val
    this.overlay.children[0].size = this._size
    this.overlay.children[1].size = 0.8 * this._size
    this.overlay.children[2].size = 1.3 * this._size
  }

  get show() {
    return this._show
  }

  set show(val) {
    this._show = val
    this.overlay.children.forEach(item => {
      item.visible = val
    })
  }

  get showAxis() {
    return this.axisVisibility.x || this.axisVisibility.y || this.axisVisibility.z
  }

  set showAxis(val) {
    ['translate', 'rotate', 'scale'].forEach(type => {
      this.setAxisVisibility(type, 'x', val)
      this.setAxisVisibility(type, 'y', val)
      this.setAxisVisibility(type, 'z', val)
    }
    )
  }

  get showX() {
    return this.axisVisibility.x
  }

  set showX(val) {
    ['translate', 'rotate', 'scale'].forEach(type => this.setAxisVisibility(type, 'x', val))
  }

  get showY() {
    return this.axisVisibility.y
  }

  set showY(val) {
    ['translate', 'rotate', 'scale'].forEach(type => this.setAxisVisibility(type, 'y', val))
  }

  get showZ() {
    return this.axisVisibility.z
  }

  set showZ(val) {
    ['translate', 'rotate', 'scale'].forEach(type => this.setAxisVisibility(type, 'z', val))
  }
}
